import wx
import sys
import os.path
import __main__

from plugins.base.pane import Pane
from projectInfo import *
from projectFileParser import ProjectFileParser
from projectFileCreator import ProjectFileCreator
from projectImporter import ProjectImporter
from projectNewDialog import ProjectNewDlg
from utils.eventHandler import EventHandler, EventArgs
from pySourceParser import *
from utils import images
from utils import tracer

class ProjectBrowser(Pane):  
  def __init__(self, parent):
    Pane.__init__(self, parent)
    self._projFile = ''
    self._projInfo = None
    self._projChanged = False

    sizer = wx.BoxSizer(wx.VERTICAL)
    self.SetSizer(sizer)

    if wx.Platform == '__WXGTK__':
      self._toolbar = self.createToolbar()
      sizer.Add(self._toolbar, False, wx.EXPAND)
    
    self._projTree = wx.TreeCtrl(self)    
    sizer.Add(self._projTree, True, wx.EXPAND)

    self._imageIndexes = {images.IMG_PROJECT:-1, images.IMG_PACKAGE:-1, images.IMG_MODULE:-1, 
                          images.IMG_CLASS:-1, images.IMG_METHOD:-1, images.IMG_IMPORT:-1, 
                          images.IMG_CONFIG_FILE:-1, images.IMG_INI_FILE:-1, 
                          images.IMG_XML_FILE:-1, images.IMG_TEXT_FILE:-1, images.IMG_IMAGE_FILE:-1}
    self._imageList = self.createImageList()
    if not self._imageList is None:
      self._projTree.SetImageList(self._imageList)

    wx.CallAfter(self.Layout)

    # event handler
    self._openFileEventHandler = EventHandler()
    self._gotoLineEventHandler = EventHandler()

    # bind tree event
    self._projTree.Bind(wx.EVT_LEFT_DCLICK, self.onLeftDClick)

  def createImageList(self):
    imageKeys = {}
    imageList = wx.ImageList(16, 16)

    for imageKey in self._imageIndexes.keys():
      image = images.getImage(imageKey)
      if not image is None:
        index = imageList.Add(image)
        self._imageIndexes[imageKey] = index
      else:
        self._imageIndexes[imageKey] = -1

    tracer.writeln('Project tree had added %d images to image list.' % imageList.GetImageCount())

    return imageList

  def createToolbar(self):
    toolbar = wx.ToolBar(self, -1, wx.DefaultPosition, wx.DefaultSize,
                        wx.TB_FLAT | wx.TB_NODIVIDER)
    toolbar.SetToolBitmapSize(wx.Size(20, 20))
    
    iconSize = wx.Size(16, 16)

    bmp = wx.ArtProvider.GetBitmap(wx.ART_NEW, wx.ART_TOOLBAR, iconSize)
    toolbar.AddLabelTool(10, "New", bmp, bmp, wx.ITEM_NORMAL, 'New Project')
    toolbar.Bind(wx.EVT_TOOL, self.onNewProject, id=10)

    bmp = wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_TOOLBAR, iconSize)
    toolbar.AddLabelTool(20, "Open", bmp, bmp, wx.ITEM_NORMAL, 'Open Project')
    toolbar.Bind(wx.EVT_TOOL, self.onOpenProject, id=20)

    bmp = wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE, wx.ART_TOOLBAR, iconSize)
    toolbar.AddLabelTool(30, "Save", bmp, bmp, wx.ITEM_NORMAL, 'Save Project')
    toolbar.Bind(wx.EVT_TOOL, self.onSaveProject, id=30)

    bmp = wx.ArtProvider.GetBitmap(wx.ART_NEW, wx.ART_TOOLBAR, iconSize)
    toolbar.AddLabelTool(40, "Add Module", bmp, bmp, wx.ITEM_NORMAL, 'Add Module')
    toolbar.Bind(wx.EVT_TOOL, self.onAddModule, id=40)

    bmp = wx.ArtProvider.GetBitmap(wx.ART_NEW_DIR, wx.ART_TOOLBAR, iconSize)
    toolbar.AddLabelTool(50, "Add Package", bmp, bmp, wx.ITEM_NORMAL, 'Add Package')
    toolbar.Bind(wx.EVT_TOOL, self.onAddPackage, id=50)

    bmp = wx.ArtProvider.GetBitmap(wx.ART_DELETE, wx.ART_TOOLBAR, iconSize)
    toolbar.AddLabelTool(60, "Delete", bmp, bmp, wx.ITEM_NORMAL, 'Delete Selected Item')
    toolbar.Bind(wx.EVT_TOOL, self.onDeleteSelectedItem, id=60)

    return toolbar

  def getConfigFileName(self):
    return os.path.dirname(__file__) + os.path.sep + 'config.cfg'

  def getProjectModified(self):
    return self._projChanged

  def getMainScript(self):
    if self._projInfo is None:
      return None
    mainScript = self._projInfo.getPath() + os.path.sep + self._projInfo.getMainScript()
    mainScript = os.path.abspath(mainScript)
    if os.path.isfile(mainScript):
      return mainScript
    return None

  def setProjectModified(self, value):
    self._projChanged = value
    rootId = self._projTree.GetRootItem()
    if self._projChanged:
      self._projTree.SetItemText(rootId, '*' + self._projInfo.getName())
    else:
      self._projTree.SetItemText(rootId, self._projInfo.getName())

  def openProject(self, filename=''):
    if filename == '':
      wildcard = "Project File (*.pyproj)|*.pyproj|"     \
               "All files (*.*)|*.*"
  
      dlg = wx.FileDialog(None, message='Choose a file',
                               defaultDir = __main__.app.globalSettings().getWorkingPath(),
                               defaultFile='',
                               wildcard=wildcard,
                               style=wx.OPEN | wx.CHANGE_DIR)
  
      if dlg.ShowModal() == wx.ID_OK:
        filename = dlg.GetPath()
      else:
        return

    assert os.path.exists(filename)

    self._projFile = filename

    parser = ProjectFileParser()
    self._projInfo = parser.parse(self._projFile)

    self.createProjectTree()
    self.setProjectModified(False)

  def saveProject(self):
    if self._projInfo is None or not self.getProjectModified():
      return 

    tracer.writeln('Saving project information to project file.')

    fileCreator = ProjectFileCreator()
    fileCreator.export(self._projInfo)

    tracer.writeln('Project information has saved to project file.')

    self.setProjectModified(False)
    
  def newProject(self):
    newProjDlg = ProjectNewDlg(None)
    if newProjDlg.ShowModal() == wx.ID_OK:
      projName = newProjDlg.getProjectName()
      projName.strip()
      
      if '' == projName:
        msgBox = wx.MessageDialog(None, 'The project name could not be empty.',
                                  'Error', wx.OK | wx.ICON_ERROR)
        msgBox.ShowModal()
        msgBox.Destroy()
        return
      
      projPath = newProjDlg.getProjectPath()
      projPath = projPath.rstrip('/ \t')
      
      if newProjDlg.useExistedSrc():
        if not os.path.exists(projPath):
          msgBox = wx.MessageDialog(None, 'The path of project could not be found.\n %s' % projPath,
                                    'Error', wx.OK | wx.ICON_ERROR)
          msgBox.ShowModal()
          msgBox.Destory()
          return
        
        excludeFolders = newProjDlg.getExcludeFolders()
        excludeFolders = excludeFolders.strip('; \t')
        excludeFolderPatterns = excludeFolders.split(';')
        
        excludeFiles =  newProjDlg.getExcludeFiles()
        excludeFiles = excludeFiles.strip('; \t')
        excludeFilePatterns = excludeFiles.split(';')
        
        self.importProject(projName, projPath, excludeFolderPatterns, excludeFilePatterns)
      else:
        projPath = projPath + os.path.sep + projName
        if not os.path.exists(projPath):
          # create project folder
          os.makedirs(projPath)
          
        # create doc folder for project
        docPath = projPath + os.path.sep + 'doc'
        os.mkdir(docPath)
        
        # create src folder for project
        srcPath = projPath + os.path.sep + 'src'
        os.mkdir(srcPath)
        
        # create CREDITS file
        creditsFilePath = projPath + os.path.sep + 'CREDITS'
        creditsFile = open(creditsFilePath, 'w')
        creditsFile.close()
        
        # create HISTORY file
        historyFilePath = projPath + os.path.sep + 'HISTORY'
        historyFile = open(historyFilePath, 'w')
        historyFile.close()
        
        # create INSTALL file
        installFilePath = projPath + os.path.sep + 'INSTALL'
        installFile = open(historyFilePath, 'w')
        historyFile.close()
        
        # create NEWS file
        newsFilePath = projPath + os.path.sep + 'NEWS'
        newsFile = open(newsFilePath, 'w')
        newsFile.close()
        
        # create README file
        readmeFilePath = projPath + os.path.sep + 'README'
        readmeFile = open(readmeFilePath, 'w')
        readmeFile.close()
        
        # create TODO file
        todoFilePath = projPath + os.path.sep + 'TODO'
        todoFile = open(todoFilePath, 'w')
        todoFile.close()
        
        # create main file
        mainFilePath = srcPath + os.path.sep + 'main.py'
        mainFile = open(mainFilePath, 'w')
        mainFile.write("#!/usr/bin/python\n")
        mainFile.write("\n")
        mainFile.write("if __name__ == \'__main__\':\n")
        mainFile.write("\tprint \'hello, world!\'\n")
        mainFile.write("\n")
        mainFile.close()        
        
        self.importProject(projName, projPath)
          
  def importProject(self, projName, projPath, excludeFolderPatterns=[], excludeFilePatterns=[]):
    importer = ProjectImporter()
    proj = importer.importFromPath(projName, projPath, excludeFolderPatterns, excludeFilePatterns)
    
    fileCreator = ProjectFileCreator()
    fileCreator.export(proj)
    
    self._projFile = projPath + os.path.sep + projName + '.pyproj'

    parser = ProjectFileParser()
    self._projInfo = parser.parse(self._projFile)

    self.createProjectTree()
    self.setProjectModified(False)

  def createProjectTree(self):
    self._projTree.DeleteAllItems()

    if self._projInfo is None:
      return

    # create project root node
    rootId = self.addProjectRoot(self._projInfo)

    # add items
    for item in self._projInfo.getItems():
      if (item.getType() & ProjectItemType.Folder) == ProjectItemType.Folder:
        self.addFolderNode(rootId, item)
      elif (item.getType() & ProjectItemType.File) == ProjectItemType.File:
        self.addFileNode(rootId, item)

  def addProjectRoot(self, projInfo):
    id = self._projTree.AddRoot(projInfo.getName())

    if not self._imageIndexes is None and self._imageIndexes[images.IMG_PROJECT] >= 0:
      self._projTree.SetItemImage(id, self._imageIndexes[images.IMG_PROJECT], wx.TreeItemIcon_Normal)

    itemData = wx.TreeItemData()
    itemData.SetData(projInfo)
    self._projTree.SetItemData(id, itemData)

    return id

  def addProjectNode(self, parentId, item):
    if item is None:
      return None

    id = self._projTree.AppendItem(parentId, item.getName())
    itemData = wx.TreeItemData()
    itemData.SetData(item)
    self._projTree.SetItemData(id, itemData)

    return id

  def addImportNode(self, parentId, imp):
    if imp is None:
      return None

    pkgName = imp.getPackageName()
    moduleName = imp.getModuleName()

    if pkgName == '':
      id = self._projTree.AppendItem(parentId, 'import %s' % imp.getModuleName())
    else:
      id = self._projTree.AppendItem(parentId, 'from %s import %s' % (imp.getPackageName(), imp.getModuleName()))

    if id is None:
      return None

    if not self._imageIndexes is None and self._imageIndexes[images.IMG_IMPORT] >= 0:
      self._projTree.SetItemImage(id, self._imageIndexes[images.IMG_IMPORT], wx.TreeItemIcon_Normal)
      
    itemData = wx.TreeItemData()
    itemData.SetData(imp)
    self._projTree.SetItemData(id, itemData)

    return id

  def addClassNode(self, parentId, cls):
    if cls is None:
      return None

    id = self._projTree.AppendItem(parentId, 'class %s' % cls.getName())
    if id is None:
      return None

    if not self._imageIndexes is None and self._imageIndexes[images.IMG_CLASS] >= 0:
      self._projTree.SetItemImage(id, self._imageIndexes[images.IMG_CLASS], wx.TreeItemIcon_Normal)

    itemData = wx.TreeItemData()
    itemData.SetData(cls)
    self._projTree.SetItemData(id, itemData)

    return id

  def addMethodNode(self, parentId, method):
    if method is None:
      return None

    paramlist = method.getParams()
    params = ''
    for param in paramlist:
      if params == '':
        params = param
      else:
        params = '%s, %s' % (params, param)
        
    id = self._projTree.AppendItem(parentId, 'def %s(%s)' % (method.getName(), params))
    if id is None:
      return None

    if not self._imageIndexes is None and self._imageIndexes[images.IMG_METHOD] >= 0:
      self._projTree.SetItemImage(id, self._imageIndexes[images.IMG_METHOD], wx.TreeItemIcon_Normal)

    itemData = wx.TreeItemData()
    itemData.SetData(method)
    self._projTree.SetItemData(id, itemData)

    return id

  def addFolderNode(self, parentId, projItem):
    id = self.addProjectNode(parentId, projItem)
    if id is None:
      return None

    if not self._imageIndexes is None and self._imageIndexes[images.IMG_PACKAGE] >= 0:
      self._projTree.SetItemImage(id, self._imageIndexes[images.IMG_PACKAGE], wx.TreeItemIcon_Normal)

    folders = []
    files = []
    for subItem in projItem.getItems():
      if (subItem.getType() & ProjectItemType.Folder) == ProjectItemType.Folder:
        folders.append(subItem)
      elif (subItem.getType() & ProjectItemType.File) == ProjectItemType.File:
        files.append(subItem)

    folders.sort(cmp=lambda x, y: cmp(x.getName(), y.getName()))
    files.sort(cmp=lambda x, y: cmp(x.getName(), y.getName()))

    # add folder nodes
    for folder in folders:
      self.addFolderNode(id, folder)

    # add file nodes
    fileCategories = {}
    for file in files:
      fileType = file.getType()
      if not fileCategories.has_key(fileType):
        fileCategories[fileType] = []
      fileCategories[fileType].append(file)

    keys = fileCategories.keys()
    keys.sort()
    for key in keys:
      for file in fileCategories[key]:
        self.addFileNode(id, file)

  def addFileNode(self, parentId, projItem):
    id = self.addProjectNode(parentId, projItem)
    if id is None:
      return None

    if not self._imageIndexes is None:
      if self._imageIndexes[images.IMG_MODULE] >= 0 and projItem.getType() == ProjectItemType.PyFile:
        self._projTree.SetItemImage(id, self._imageIndexes[images.IMG_MODULE], wx.TreeItemIcon_Normal)
      elif self._imageIndexes[images.IMG_MODULE] >= 0 and projItem.getType() == ProjectItemType.CfgFile:
        self._projTree.SetItemImage(id, self._imageIndexes[images.IMG_CONFIG_FILE], wx.TreeItemIcon_Normal)
      elif self._imageIndexes[images.IMG_MODULE] >= 0 and projItem.getType() == ProjectItemType.IniFile:
        self._projTree.SetItemImage(id, self._imageIndexes[images.IMG_INI_FILE], wx.TreeItemIcon_Normal)
      elif self._imageIndexes[images.IMG_MODULE] >= 0 and projItem.getType() == ProjectItemType.XmlFile:
        self._projTree.SetItemImage(id, self._imageIndexes[images.IMG_XML_FILE], wx.TreeItemIcon_Normal)
      elif self._imageIndexes[images.IMG_MODULE] >= 0 and projItem.getType() == ProjectItemType.ImgFile:
        self._projTree.SetItemImage(id, self._imageIndexes[images.IMG_IMAGE_FILE], wx.TreeItemIcon_Normal)
      elif self._imageIndexes[images.IMG_MODULE] >= 0 and projItem.getType() == ProjectItemType.File:
        self._projTree.SetItemImage(id, self._imageIndexes[images.IMG_TEXT_FILE], wx.TreeItemIcon_Normal)

    if os.path.exists(projItem.getFullname()) and projItem.getType() == ProjectItemType.PyFile:
      self.addModuleInfo(id, projItem)

  def addModuleInfo(self, parentId, fileItem):
    if parentId == None or fileItem is None:
      return

    if fileItem.getType() != ProjectItemType.PyFile:
      return 
    
    parser = PySourceParser()
    parser.parse(fileItem.getFullname())

    # add imports nodes
    for imp in parser.getImports():
      self.addImportNode(parentId, imp)
      
    # add class nodes
    classes = parser.getClasses()
    classNames = classes.keys()
    classNames.sort()
    for name in classNames:
      cls = classes[name]
      id = self.addClassNode(parentId, cls)

      # add method nodes
      methods = cls.getMethods()
      methodNames = methods.keys()
      methodNames.sort()
      for name in methodNames:
        mth = methods[name]
        self.addMethodNode(id, mth)
      
    # add global method modes
    gMths = parser.getGlobalMethods()
    gMthNames = gMths.keys()
    gMthNames.sort()
    for name in gMthNames:
      gMth = gMths[name]
      self.addMethodNode(parentId, gMth)

  def insertProjectNode(self, parentNodeId, projItem):
    if parentNodeId is None:
      return False

    newItemName = projItem.getName()
    newItemType = projItem.getType()

    id = None
    index = 0
    childId, cookie = self._projTree.GetFirstChild(parentNodeId)
    while childId.IsOk():
      itemData = self._projTree.GetItemData(childId)
      itemInfo = itemData.GetData()
      itemType = itemInfo.getType()
      itemName = itemInfo.getName()

      if itemType > newItemType:
        id = self._projTree.InsertItemBefore(parentNodeId, index, newItemName)
        break
      elif itemType == newItemType and itemName > newItemName:
        id = self._projTree.InsertItemBefore(parentNodeId, index, newItemName)
        break
      else:
        childId, cookie = self._projTree.GetNextChild(parentNodeId, cookie)
        index += 1

    if not id is None:
      itemData = wx.TreeItemData()
      itemData.SetData(projItem)
      self._projTree.SetItemData(id, itemData)

      if not self._imageIndexes is None:
        if newItemType == ProjectItemType.Folder and self._imageIndexes[images.IMG_PACKAGE] >= 0:
          self._projTree.SetItemImage(id, self._imageIndexes[images.IMG_PACKAGE], wx.TreeItemIcon_Normal)
        elif newItemType == ProjectItemType.PyFile and self._imageIndexes[images.IMG_MODULE] >= 0:
          self._projTree.SetItemImage(id, self._imageIndexes[images.IMG_MODULE], wx.TreeItemIcon_Normal)
        elif newItemType == ProjectItemType.CfgFile and self._imageIndexes[images.IMG_CONFIG_FILE] >= 0:
          self._projTree.SetItemImage(id, self._imageIndexes[images.IMG_CONFIG_FILE], wx.TreeItemIcon_Normal)
        elif newItemType == ProjectItemType.IniFile and self._imageIndexes[images.IMG_INI_FILE] >= 0:
          self._projTree.SetItemImage(id, self._imageIndexes[images.IMG_INI_FILE], wx.TreeItemIcon_Normal)
        elif newItemType == ProjectItemType.XmlFile and self._imageIndexes[images.IMG_XML_FILE] >= 0:
          self._projTree.SetItemImage(id, self._imageIndexes[images.IMG_XML_FILE], wx.TreeItemIcon_Normal)
        elif newItemType == ProjectItemType.ImgFile and self._imageIndexes[images.IMG_IMAGE_FILE] >= 0:
          self._projTree.SetItemImage(id, self._imageIndexes[images.IMG_IMAGE_FILE], wx.TreeItemIcon_Normal)
        elif newItemType == ProjectItemType.File and self._imageIndexes[images.IMG_TEXT_FILE] >= 0:
          self._projTree.SetItemImage(id, self._imageIndexes[images.IMG_TEXT_FILE], wx.TreeItemIcon_Normal)

      self.setProjectModified(True)

      if (newItemType & ProjectItemType.PyFile) == ProjectItemType.PyFile:
        self.addModuleInfo(id, projItem)
      return True

    return False

  def findProjectNode(self, projItem, startItemId=None, cookie=None):
    if startItemId is None:
      startItemId = self._projTree.GetRootItem()

    itemData = self._projTree.GetItemData(startItemId)
    itemInfo = itemData.GetData()

    if itemInfo == projItem:
      return startItemId

    if self._projTree.GetChildrenCount(startItemId) > 0:
      child, cookie = self._projTree.GetFirstChild(startItemId)
      while child.IsOk():
        findId = self.findProjectNode(projItem, child, cookie)
        if not findId is None:
          return findId
        else:
          child, cookie = self._projTree.GetNextChild(startItemId, cookie)

    return None

  # -- methods -----------------------------------------------------
  def deleteSelectedItem(self):
    selectedItemId = self._projTree.GetSelection()
    if selectedItemId is None:
      return

    itemData = self._projTree.GetItemData(selectedItemId)
    assert not itemData is None

    itemInfo = itemData.GetData()
    assert not itemInfo is None

    self._projInfo.removeItem(itemInfo.getFullname())
    self._projTree.Delete(selectedItemId)

    self.setProjectModified(True)

  def addModule(self, path=''):
    if self._projInfo is None:
      return

    if path == '' or not os.path.exists(path):
      wildcard = "Python source (*.py)|*.py|"     \
                 "All files (*.*)|*.*"
      
      dlg = wx.FileDialog(None, message='Choose a file',
                                 defaultDir = self._projInfo.getPath(),
                                 defaultFile='',
                                 wildcard=wildcard,
                                 style=wx.OPEN | wx.CHANGE_DIR | wx.MULTIPLE)

      if dlg.ShowModal() == wx.ID_OK:
        path = dlg.GetPath()

      dlg.Destroy()

    if not os.path.exists(path):
      try:
        fs = open(os.path.realpath(path), 'w')
        fs.flush()
        fs.close()
      except:
        return

    addedItem = self._projInfo.addItem(path)
    if addedItem is None:
      raise Exception('Can not add file information to project. %sFile Name: %s' % (os.linesep, path))

    tracer.writeln('-- Module %s had been added ---------------------' % addedItem.getName())
    self._projInfo.dump()

    parentProjItem = addedItem.getParent()
    treeItemId = self.findProjectNode(parentProjItem, None, None)
    if not treeItemId is None:
      self.insertProjectNode(treeItemId, addedItem)

  def addPackage(self, path=''):
    if self._projInfo is None:
      return

    if path == '' or not os.path.exists(path):
      dlg = wx.DirDialog(self, "Choose a directory:",
                        defaultPath = self._projInfo.getPath(),
                        style=wx.DD_DEFAULT_STYLE)

      if dlg.ShowModal() == wx.ID_OK:
        path = dlg.GetPath()

      dlg.Destroy()

    if not os.path.exists(path):
      if sys.platform == '__WXGTK__':
        os.system('mkdir %s' % path)
      elif sys.platform == '__WXMSW__':
        os.system('md %s' % path)
      else:
        return
        
    newPackageInfo = self._projInfo.addItem(path)
    if newPackageInfo is None:
      raise Exception('Can not add package information to project. %sPackage Path: %s' % (os.linesep, path))

    tracer.writeln('-- Package %s had been added ---------------------' % newPackageInfo.getName())
    self._projInfo.dump()

    parentProjItem = newPackageInfo.getParent()
    treeItemId = self.findProjectNode(parentProjItem, None, None)
    if not treeItemId is None:
      self.insertProjectNode(treeItemId, newPackageInfo)
      
    initFileName = os.path.normpath(path) + os.path.sep + '__init__.py'

    if not os.path.exists(initFileName):
      if wx.MessageDialog(self, 'The __init__.py does not find.%sDo you want to create it?' % os.linesep,
          'Notification', wx.YES | wx.NO | wx.ICON_INFORMATION).ShowModal() == wx.ID_YES:
        try:
          fs = open(os.path.realpath(initFileName), 'w')
          fs.flush()
          fs.close()
        except:
          return
    
        initFileInfo = ProjectItem('__init__.py', ProjectItemType.PyFile, newPackageInfo)
        newPackageInfo.getItems().append(initFileInfo)

        treeItemId = self.findProjectNode(newPackageInfo, None, None)
        if not treeItemId is None:
          self.insertProjectNode(treeItemId, initFileInfo)

  def refreshModuleInfo(self, path):
    assert os.path.exists(path)

    if self._projInfo is None:
      return

    itemInfo = self._projInfo.findItemByPath(path)
    if itemInfo is None:
      return

    if itemInfo.getType() != ProjectItemType.PyFile:
      return

    itemNode = self.findProjectNode(itemInfo)
    if itemNode is None:
      return

    itemInfo.clearItems()
    self._projTree.DeleteChildren(itemNode)
    self.addModuleInfo(itemNode, itemInfo)
      

  # -- Event Handlers ----------------------------------------------
  def openFileEventHandler(self, handler):
    self._openFileEventHandler.add(handler)

  def onOpenFile(self, filename):
    eventArgs = EventArgs((filename,))

    self._openFileEventHandler.invoke(self, eventArgs)

  def gotoLineEventHandler(self, handler):
    self._gotoLineEventHandler.add(handler)

  def onGotoLine(self, filename, lineNo):
    eventArgs = EventArgs((filename, lineNo))
    self._gotoLineEventHandler.invoke(self, eventArgs)

  # -- TreeCtrl Events ---------------------------------------------
  def onLeftDClick(self, evt):
    pt = evt.GetPosition();
    itemId, flags = self._projTree.HitTest(pt)
    if itemId:
      itemData = self._projTree.GetItemData(itemId)
      itemInfo = itemData.GetData()
      itemType = type(itemInfo)
      if itemType is ProjectItem and (itemInfo.getType() & ProjectItemType.File) == ProjectItemType.File:
        filename = itemInfo.getFullname()
        self.onOpenFile(filename)
      elif itemType is ImportInfo or itemType is ClassInfo or itemType is MethodInfo:
        filename = itemInfo.getFilename()
        lineNo = itemInfo.getLineNo()
        self.onGotoLine(filename, lineNo)
      else:
        if self._projTree.IsExpanded(itemId):
          self._projTree.Collapse(itemId)
        else:
          self._projTree.Expand(itemId)
    else:
      evt.Skip()
      
  # -- Toolbar Events
  def onAddModule(self, evt):
    self.addModule()

  def onAddPackage(self, evt):
    self.addPackage()
  
  def onNewProject(self, evt):
    self.newProject()

  def onDeleteSelectedItem(self, evt):
    self.deleteSelectedItem()

  def onOpenProject(self, evt):
    self.openProject()

  def onSaveProject(self, evt):
    self.saveProject()
